package com.sky.sky_common.util;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Map;

import javax.crypto.SecretKey;

import org.springframework.stereotype.Component;

import com.sky.sky_common.config.JwtProperties;
import com.sky.sky_common.constant.JwtRoleConstant;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import jakarta.annotation.PostConstruct;

@Component
public class JwtService {
    private final JwtProperties jwtProperties;
    private SecretKey adminKey;
    private SecretKey userKey;
    private SecretKey currKey;

    public JwtService(JwtProperties jwtProperties) {
        this.jwtProperties = jwtProperties;
    }

    @PostConstruct
    public void init(){
        // Base64 编码密钥
        // String base64Secret = Base64.getEncoder().encodeToString(jwtProperties.getSecret().getBytes());

        // 从 Base64 密钥构建 SecretKey（比直接 getBytes 安全）
        byte[] bytes = Decoders.BASE64.decode(jwtProperties.getAdminSecret());
        // 只要 secret 一样，生成的 key 就一样
        // 当长度不足 32 字节时，该方法会抛出异常，避免在弱密钥上继续运行（这是它的价值之一）
        this.adminKey = Keys.hmacShaKeyFor(bytes);// HMAC-SHA 算法

        byte[] bytesUser = Decoders.BASE64.decode(jwtProperties.getUserSecret());
        this.userKey = Keys.hmacShaKeyFor(bytesUser);
    }

    /**
     * 获取令牌
     * @Param subject 通常用 username 或 userId
     * @Param claims 放自定义信息
     */
    public String genJwtToken(String subject, Map<String, Object> claims, String role) {
        Integer expire = jwtProperties.getAdminExpire();
        currKey = adminKey;
        // role忽略大小写
        if(role.toLowerCase() == JwtRoleConstant.USER){
            expire = jwtProperties.getUserExpire();
            currKey = userKey;
        }
        // 当前时间
        Instant now = Instant.now();
        String token = Jwts.builder()
                .subject(subject) //主题
                .claims(claims) //声明
                .issuedAt(Date.from(now)) //签发时间
                .expiration(Date.from(now.plus(expire, ChronoUnit.MINUTES))) //过期时间
                .signWith(currKey) //签名
                .compact();
        return token; 
    }

    /**
     * 检验并返回 Claims(过期，无效则抛出异常)
     */
    public Claims parseJwtToken(String token, String role) {
        currKey = adminKey;
        if(role.toLowerCase() == JwtRoleConstant.USER){
            currKey = userKey;
        }
        Claims claims = Jwts.parser().clockSkewSeconds(120)// 允许的时钟偏移时间,单位秒
                .verifyWith(currKey) // 验证签名
                .build() // 构建, 如果验证失败则抛出异常
                .parseSignedClaims(token) // 解析 token
                .getPayload(); // 获取 Claims
        return claims;
    }
}
